use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct PaginationPageInfo {
    pub has_next: bool,
    pub has_prev: bool,
    pub current_page:usize,
    pub current_size:usize,
}
#[derive(Debug, Clone, Serialize)]
pub struct Pagination<T>
where
    T: Serialize,
{
    pub items: Vec<T>,
    pub page_info: PaginationPageInfo,
    pub total_count: usize,
}
pub trait ToPagination<T>
where
    T: Serialize,
{
    /// 进行分页
    ///
    /// 适用于缓存查询结果
    fn to_pagination(&self, page: usize, size: usize) -> Pagination<T>;
    /// 转换到`Pagination`  
    ///
    /// 适用于数据库查询结果直转
    fn into_pagination(&self,page:usize,total:usize) -> Pagination<T>;
}
macro_rules! impl_array_to_pagination {
    () => {
        fn to_pagination(&self, page: usize, size: usize) -> Pagination<T> {
            let len = self.len();
            let has_next = (page + 1) * size < len;
            let has_prev = page > 0 && len > 0;
            let current_len = {
                if has_next {
                    size
                } else {
                    len - page * size
                }
            };
            let mut slice = Vec::with_capacity(current_len);
            let t = &self[(page * size)..(page * size + current_len)];
            slice.extend_from_slice(t);

            Pagination {
                total_count: len,
                items: slice,
                page_info: PaginationPageInfo { has_next, has_prev,current_page:page,current_size:size },
            }
        }
    };
}
macro_rules! impl_array_into_pagination {
    () => {
        fn into_pagination(&self, page:usize, total:usize) -> Pagination<T> {
            let size = self.len();
            let has_next = (page + 1) * size <total;
            let has_prev = page>0 && total>0;
            let slice = self.to_vec();
    
           Pagination {
               total_count:total,
               items:slice,
               page_info:PaginationPageInfo{
                   has_next,
                   has_prev,
                   current_page:page,
                   current_size:size
               }
           }
        }
    };
}
impl<T> ToPagination<T> for Vec<T>
where
    T: Serialize + Clone,
{
    impl_array_to_pagination!();
    impl_array_into_pagination!();
}
impl<'a, T,const LENGTH:usize> ToPagination<T> for &'a [T;LENGTH]
where
    T: Serialize + Clone,
{
    impl_array_to_pagination!();
    impl_array_into_pagination!();
}
impl<'a, T> ToPagination<T> for &'a[T]
where
    T: Serialize + Clone,
{
    impl_array_to_pagination!();
    impl_array_into_pagination!();
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_vec_to_pagination() {
        {
            let vec = vec![1,2,3,4,5,6,7,8,9,10];
            let pagination= vec.to_pagination(0, 10);
            assert_eq!(pagination.total_count,10);
            assert_eq!(pagination.page_info.has_prev,false);
            assert_eq!(pagination.page_info.has_next,false);
            assert_eq!(pagination.items.len(),10);
        }
        {
            let slice = &[1,2,3,4,5,6,7,8,9];
            let pagination  = slice.to_pagination(0, 10);
            assert_eq!(pagination.total_count,9);
            assert_eq!(pagination.page_info.has_prev,false);
            assert_eq!(pagination.page_info.has_next,false);
        }

        {
            let slice:&[i32] = &[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
            let pagination = slice.to_pagination(1, 10);
            assert_eq!(pagination.total_count,15);
            assert_eq!(pagination.page_info.has_prev,true);
            assert_eq!(pagination.page_info.has_next,false);
            assert_eq!( pagination.items.len(),5);
        }
    }
    #[test]
    fn test_vec_into_pagination() {
        {
            let vec = vec![1,2,3,4,5,6,7,8,9,10];
            let pagination = vec.into_pagination(3, 41);
            assert_eq!(pagination.total_count,41);
            assert_eq!(pagination.items.len(),10);
            assert_eq!(pagination.page_info.has_prev,true);
            assert_eq!(pagination.page_info.has_next,true);
            assert_eq!(pagination.page_info.current_page,3);
            assert_eq!(pagination.page_info.current_size,10);
        }
        {
            let slice = &[1,2,3,4,5,6,7,8,9];
            let pagination = slice.into_pagination(0, 9);
            assert_eq!(pagination.total_count,9);
            assert_eq!(pagination.page_info.has_prev,false);
            assert_eq!(pagination.page_info.has_next,false);
        }
        {
            let slice:&[i32] = &[1,2,3,4,5,6,7,8,9];
            let pagination = slice.into_pagination(0, 9);
            assert_eq!(pagination.total_count,9);
            assert_eq!(pagination.page_info.has_prev,false);
            assert_eq!(pagination.page_info.has_next,false);
        }
    }
}
